跳到主要内容

django 模版渲染


[toc]

4.模版渲染

4.1 settings文件配置

settings配置文件中的TEMPLATES项是对静态页面的设置,DIRS处需要写上对应的静态文件存放的位置,默认为templates

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')] #别忘了配置这个路径
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

4.2 模版语法

在html文件标签中写

{{ 变量 }}   {% 逻辑 %}

4.3 万能的点 .

html文件

以下代码中dic.name就是.的运用

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ num }}</h1>
<h1>{{ str }}</h1>
<h1>{{ lst }}</h1>
<h1>{{ dic.name }}</h1>
{# #注意,调用方法时,不能加括号,所有如果方法带参数,就没法用了#}
<h1>{{ woman.play }}</h1>
<h1>{{ woman.xx }}</h1>

</body>
</html>

views文件

from django.shortcuts import render,HttpResponse,redirect
from django.views import View #CBV进程的类
# Create your views here.

def home(request):
# return HttpResponse('登陆成功')
# return render(request,'index.html')
num = 10
str = 'I am a running 的草泥马'
lst = [1,2,3,4,5,6]
dic = {'name':'小明','age':20}

class A:
money = 100
def __init__(self):
self.xx = 'oo'
def play(self):
return '什么价位?'
woman = A()

return render(request,'模版渲染.html',{'num':num,'str':str,'lst':lst,'dic':dic,'woman':woman})

运行后的初次效果

iShot_2024-08-30_10.53.46

4.4 过滤器

4.4.1 过滤器用法

有参数的过滤器用法

{{ 变量|过滤器名称:'参数' }}

没参数的过滤器用法

{{ 变量|过滤器名称 }}

4.4.2 内置过滤器

views文件

from django.shortcuts import render,HttpResponse,redirect
from django.views import View #CBV进程的类
# Create your views here.

def home(request):
# return HttpResponse('登陆成功')
# return render(request,'index.html')
num = 10
str = 'I am a running 的草泥马'
lst = [1,2,3,4,5,6]
dic = {'name':'小明','age':20}

class A:
money = 100
def __init__(self):
self.xx = 'oo'
def play(self):
return '什么价位?'
woman = A()

return render(request,'模版渲染.html',{'num':num,'str':str,'lst':lst,'dic':dic,'woman':woman})
4.4.2.1 truncatechars 截断字符串

truncatechars:数字 数字表示要截断的字符数

未截断前

iShot_2024-08-30_10.58.54

截断后

truncatechars:5表示截取5个字符,其中包括3个.

<h1>{{ str | truncatechars:5 }}</h1>

iShot_2024-08-30_11.00.47

4.4.2.2 default 如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值

在views文件中只有num变量,没有num1变量,因此使用default指定的值

<h1>{{ num1 | default:'没有num1这个变量' }}</h1>

iShot_2024-08-30_11.01.54

4.4.2.3 length 获取变量数据长度
<h1>{{ lst | length }}</h1>
4.4.2.4 filesizeformat 大小按照人类可读方式显示
views文件中定义file_size = 1024,注意还需要在render方法中以字典的形式定义返回

<h1>{{ file_size | filesizeformat }}</h1>

iShot_2024-08-30_11.02.51

4.4.2.5 slice 切片(顾头不顾腚)
<h1>{{ str | slice:'2:9' }}</h1>

iShot2020-10-16 14.26.06

使用切片截取

iShot_2024-08-30_11.04.40

4.4.2.6 date 日期格式化显示
views文件
import datetime
now = datetime.datetime.now()
注意在render方法中返回

html文件
<h1>{{ now | date:'Y-m-d H:i:s' }}</h1>

iShot_2024-08-30_11.05.35

4.4.2.7 safe 关闭HTML的自动转义

safe是防止xss攻击让一些js、html等等代码变成普通字符而不执行,但有的时候我们想要执行这些代码,就需要用到safe

Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样就可以搞一些坏事儿了,写个弹窗的死循环,浏览器会一直弹窗,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过 过滤器"|safe" 的方式告诉Django这段代码是安全的不必转义。

views文件中定义了一个a_tag,我门现在就想让这个标签成为一个超链接
a_tag = "<a href='http://www.baidu.com'>百度</a>"

html文件
<h1>{{ a_tag | safe }}</h1>

没有加safe

iShot_2024-08-30_11.08.21

加上safe后

iShot_2024-08-30_11.10.36

4.4.2.8 join 字符串拼接列表
views文件
lst = [1,2,3,4,5,6]

html文件
<h1>{{ lst | join:"+"}}</h1>

iShot_2024-08-30_11.12.02

4.4.2.9 cut 移除变量中所有的与给出的变量相同的字符串
views文件
str = 'I am a running 的草泥马'

html文件
<h1>{{ str | cut:' ' }}</h1>

iShot_2024-08-30_11.12.59

4.5 标签

4.5.1 for标签

for标签语法

{% for foo in 循环的对象 %}

{% endfor %}

for标签循环列表简单示例

views文件

def home(request):
lst = [1,2,3,4,5]
return render(request,'home.html',{'lst':lst})

html文件

<body>
<ul>
{% for foo in lst %}
<li>{{ foo }}</li>
{% endfor %}
</ul>
</body>

结果如下

iShot_2024-08-30_11.16.48

<body>
<ul>
{% for foo in lst reversed %}
<li>{{ foo }}</li>
{% endfor %}
</ul>
</body>

iShot_2024-08-30_11.18.22

for标签循环字典简单示例

views文件

def home(request):
lst = [1,2,3,4,5]
dic = {'name':'小明','age':20,'hobby':'唱、跳、rap、篮球'}
return render(request,'home.html',{'lst':lst,'dic':dic})

html文件

<ol>
{% for foo in dic.items %} //这里可以循环字典的键、值、键和值
<li>{{ foo }}</li>
{% endfor %}
</ol>


<ol>
{% for key,value in dic.items %}
<li>{{ key }}--->{{ value }}</li>
{% endfor %}
</ol>

iShot_2024-08-30_11.24.34

iShot_2024-08-30_11.25.39

for标签中的empty

 {% for i in lst1 %} #当没有数据时,会生成empty的内容
<li>{{ i }}</li>
{% empty %}
<p>啥数据也没有!</p>
{% endfor %}

for标签中的forloop方法,必须在循环内使用

forloop.counter            #当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能
forloop.counter0 #当前循环的索引值(从0开始)
forloop.revcounter #当前循环的倒序索引值(从1开始)
forloop.revcounter0 #当前循环的倒序索引值(从0开始)
forloop.first #当前循环是不是第一次循环(布尔值)
forloop.last #当前循环是不是最后一次循环(布尔值)
forloop.parentloop #本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

forloop.counter #当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能

<ol>
{% for key,value in dic.items %}
<li>{{ forloop.counter }}{{ key }}--->{{ value }}</li>
{% endfor %}
</ol>

iShot_2024-08-30_11.26.49

forloop.counter0 #当前循环的索引值(从0开始)

<ol>
{% for key,value in dic.items %}
<li>{{ forloop.counter0 }}{{ key }}--->{{ value }}</li>
{% endfor %}
</ol>

iShot_2024-08-30_11.29.18

forloop.first #当前循环是不是第一次循环(布尔值)

<ol>
{% for key,value in dic.items %}
<li>{{ forloop.first }} {{ key }}--->{{ value }}</li>
{% endfor %}
</ol>

iShot_2024-08-30_11.33.34

forloop.parentloop #本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

views文件

def home(request):
lst = [1,2,3,4,5]
dic = {'name':'小明','age':20,'hobby':['唱','跳','rap','篮球']}
return render(request,'home.html',{'lst':lst,'dic':dic})

html文件

<ol>
{% for key,value in dic.items %}
<li>{{ forloop.last }} {{ key }}--->{{ value }}</li>
{% for foo in dic.hobby %}
{{ forloop.parentloop.counter }}---{{ forloop.counter }}<a href="">{{ foo }}</a>
{% endfor %}
{% endfor %}
</ol>

iShot_2024-08-30_11.34.58

4.5.2 if标签

if语句支持 andor==><!=<=>=innot inisis not 判断,注意条件两边都有空格

views文件

def home(request):
num = 100
str = 'helow'
lst = [1,2,3,4,5]
dic = {'name':'小明','age':20,'hobby':'唱、跳、rap、篮球'}
return render(request,'home.html',{'lst':lst,'dic':dic,'num':num,'str':str})

html文件

普通判断

{% if num == 100 %}
<p>数字等于100</p>
{% else %}
<p>数字不等于100</p>
{% endif %}


#语法
{% if %}
{% elif %}
{% else %}
{% endif %} //以endif结尾

结合过滤器使用

{% if str|length == 5 %}
<p>字符串长度为5</p>
{% endif %}

4.5.3 with标签

用于给比较长的数据调用起别名,只能在with标签中只用

views文件

def home(request):
lst = [1,2,{'name':'小明','age':20},4,5]

return render(request,'home.html',{'lst':lst}

html文件

html文件中想渲染views文件中返回的列表中的元素中的字典的值,如果每一次都写的话会比较长,例如lst.2.name,这个时候我们就可以取一个别名,用于给这个数据的调用,这样的话下次别的地方有引用的时候写起啦会比较简单

//例如,h1标签和a标签中都想引用这个数据的调用,没有起别名之前的写法,这样每次引用都需要在写一遍,比较麻烦
<h1>
{{ lst.2.name }}
</h1>
<a href="">{{ lst.2.name }}</a>


//这个时候就可以用到with别名的方法
<h1>
{% with lst.2.name as l %}
<a href="">{{ l }}</a>
{% endwith %}
</h1>

4.5.4 csrf_token 通过csrf认证机制

#写法
{% csrf_token %}

csrf_token
    我们以post方式提交表单的时候,会报错,我们在settings里面的中间件配置里面把一个csrf的防御机制给注销了,本身不应该注销的,而是应该学会怎么使用它,并且不让自己的操作被forbiden,通过这个东西就能搞定。

    这个标签用于跨站请求伪造保护,

    在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隐藏的,这个标签的值是个随机字符串,提交的时候,这个东西也被提交了,首先这个东西是我们后端渲染的时候给页面加上的,那么当你通过我给你的form表单提交数据的时候,你带着这个内容我就认识你,不带着,我就禁止你,因为后台我们django也存着这个东西,和你这个值相同的一个值,可以做对应验证是不是我给你的token,就像一个我们后台给这个用户的一个通行证,如果你用户没有按照我给你的这个正常的页面来post提交表单数据,或者说你没有先去请求我这个登陆页面,而是直接模拟请求来提交数据,那么我就能知道,你这个请求是非法的,反爬虫或者恶意攻击我的网站

4.6 自定义标签和自定义过滤器

4.6.1 自定义标签

1.在应用程序目录中创建一个templatetags目录(名称只能叫templatetags)

2.在templatetabs目录中创建xx.py

3.在xx.py中导入template

from django import template

#变量名称必须叫register
register = template.Library()

#自定义标签
@register.simple_tag
def tag(v1):
return v1 + 'tag'

使用自定义标签

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
name = 'hehe'
return render(request,'tags.html',{'name':name})

tags.html文件

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的标签
{% load xx %}
<h1>
{% tag name %}
</h1>

args.html文件中不给自定义标签传参数

iShot_2024-08-30_11.35.51

views文件中指定给自定义的标签传2个参数,v1是views中tag函数定义的变量name,v2就是args.html中自定义标签传的一个参数

from django import template

#变量名称必须叫register
register = template.Library()

#自定义标签
@register.simple_tag
def tag(v1,v2):
return v1 + 'tag' + v2

args.html文件中给自定义标签传参

<h1>
{% tag name '参数1' %}
</h1>

iShot_2024-08-30_11.36.43

4.6.2 自定义过滤器

1.在应用程序目录中创建一个templatetags目录(名称只能叫templatetags)

2.在templatetabs目录中创建xx.py

3.在xx.py中导入template

from django import template

#变量名称必须叫register
register = template.Library()

#自定义过滤器,最多2个参数 这里自定义一个过滤器,接受任意一个参数,给这个参数后边加一个字符串

@register.filter
def oo(v1):
return v1 + 'oo'

使用自定义过滤器

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
name = 'hehe'
return render(request,'tags.html',{'name':name})

tags.html

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的过滤器
{% load xx %}
<h1>
{{ name | oo }}
</h1>

结果如下,可以看到,我们自定义的过滤器,接受任意一个参数,给这个参数后边加一个字符串oo

iShot_2024-08-30_12.20.27

上述结果是xx.py就是我们自定义的过滤器文件中的函数只传了一个参数,现在我们给这个函数传2个参数(最多传两个参数)

xx.py写法

from django import template

#变量名称必须叫register
register = template.Library()

#自定义过滤器,最多2个参数 这里自定义一个过滤器,接受任意一个参数,给这个参数后边加一个字符串

@register.filter
def oo(v1,v2):
return v2 + 'oo' + v1

上述代码中v1是views中定义的name变量的值,也就是hehe,v2就是tags.html中函数oo后面传的参数,因此打印的结果就是
哈哈oohehe

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
name = 'hehe'
return render(request,'tags.html',{'name':name})

tags.html

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的过滤器
{% load xx %}
<h1>
{{ name | oo:'哈哈' }}
</h1>

iShot_2024-08-30_12.21.22

4.6.3 inclusion_tag 修改引入组件的样式(非常难理解)

inclusion_tag作用如下

iShot_2024-08-30_12.22.12

接下来开始整个过程

第一步、先在django项目同路径下的templates目录下创建一个菜单静态页面作为一个组件

zujian.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.menus{
width: 200px;
}
.menus .item{
background-color: green;
color: white;
height: 50px;
}
</style>
</head>
<body>
<div class="menus">
<div class="item">菜单1</div>
<div class="item">菜单2</div>
<div class="item">菜单3</div>
</div>

</body>
</html>

效果如下

iShot_2024-08-30_12.23.57

第二步、分别在urls和views文件中写上对应的访问路径和函数

这里在后边定义一个xx.html,这个xx.html引入组件文件zujian.html,并且访问路径是xx,视图中的函数也叫xx(返回xx.html)

urls文件

url(r'^xx/', views.xx),

views文件

def xx(request):
return render(request,'xx.html')

第三步、还是在templates目录下创建一个xx.html文件,这个html文件引入刚才创建的组件文件

xx.html文件初始内容如下

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.nav{
height: 200px;
width: 150px;
background-color: burlywood;
}
</style>
</head>
<body>
<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
</body>
</html>

初始xx.html

iShot_2024-08-30_12.25.35

接下来在xx.html文件中引入组件文件的样式

在div标签下引入zujian.html

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{% include 'zujian.html' %}

引入组件后的样式,绿色为zujian.html文件中的内容

iShot_2024-08-30_12.28.00

接下来想要将引入的样式中的菜单栏变为其他内容,需要做以下操作,在组件文件zujian.html文件中将想要更改的内容利用for循环便利

zujian.html文件

<div class="menus">
//利用for循环遍历data变量,foo就是data变量中的所有内容,这样的话就做成了动态的效果,原先的菜单栏div标签现在只需要写一个,因为foo是变量data中所有的值
{% for foo in data %}
<div class="item">{{ foo }}</div>
{% endfor %}

//注释之前的菜单栏,因为我们需要用到动态传入内容
{# <div class="item">菜单1</div>#}
{# <div class="item">菜单2</div>#}
{# <div class="item">菜单3</div>#}
</div>


这里有个问题,现在想把zujian.html文件中的菜单栏做一下动态修改,这里写了从data中取值,但是循环遍历的data是从哪来的???这时就引出了inclusion_tag
inclusion_tag需要写在templatetags目录下自定义的py文件中,而data就是我们自定义的返回给xx.html文件的动态内容,因为xx.html引入zujian.html的样式是固定的,只有zujian.html文件中定义的内容

第四步、在templatetags目录下创建一个mytags.py

templatetags目录是在django项目的应用程序目录下创建的目录,在自定义标签和自定义过滤器的时候必须创建这个目录,且名字只能是这个,在这个templatetags目录下创建的py文件中自定义标签和过滤器

mytags.py

@register.inclusion_tag('zujian.html')是固定写法,括号中的参数就是组件文件,这里的data是我们自定义的字典


@register.inclusion_tag('zujian.html')
def hehe(v1):
return {'data':['唱','跳','rap','篮球']}

第五步、在xx.html文件中引入动态内容

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %} //引入自定义函数的那个文件名
{% hehe %} //引入自定义函数,用于返回data

最终运行效果如下,引入的组件的背景颜色绿色没有改变,但是改变了之前的菜单栏

iShot_2024-08-30_12.29.24

整个过程总结

1.定义urls

url(r'^xx/', views.xx),

2.定义视图

def xx(request):
return render(request,'xx.html')

3.xx.html文件引入组件文件zujian.html,组件中只定义了一个背景色,但是xx.html文件想要动态的添加一些内容,例如菜单栏,此时需要在组件文件中做如下改动

组件文件中定义的背景色

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.menus{
width: 200px;
}
</style>
</head>
<body>
<div class="menus">
</div>
</body>
</html>

利用for循环去循环一个变量,例如data,这个变量是在django项目下的应用程序目录下的templatetags下的任意名称py文件中利用@register.inclusion_tag('zujian.html')和自定义函数中的return返回值定义的变量

应用程序下templates目录中定义一个mytags.py(名称任意),文件内容如下

inclusion_tag中必须跟一个参数,这个参数必须是组件文件,自定义一个函数hehe(名称任意),return的返回值会返回给组件文件

mytags.py文件内容如下

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')
def hehe():
return {'data':['唱','跳','rap','篮球']}

4.第3步中的data变量已经返回给了组件文件,因此xx.html文件中需要引入应用程序下的templatetags中定义的那个py文件(这里是mytag.py)

还需要引入这个py文件中自定义的函数的名称(这里是hehe)

mytags.py(自定义标签需要在应用程序下的templatetags目录中定义一个任意的py文件,然后在这个文件中写自定义标签内容)

xx.html文件内容如下

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %}
{% hehe %}


#参数说明
{% load mytags %} //引入应用程序下的templatetags中定义的那个py文件(这里是mytags.py)

{% hehe %} //引入这个py文件(mytags.py)中自定义的函数的名称(这里是hehe)

最终的渲染效果就由应用程序下的templatetags中定义的那个py文件(这里是mytags.py)中定义的函数中自定义的返回值决定

这里定义的data是一个字典,data会返回给组件文件用于动态渲染

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')
def hehe():
return {'data':['唱','跳','rap','篮球']}

关于动态返回内容的一个问题

写在mytags中是写死的,我们应该写成动态的,所以应该写在views中从数据库中获取数据达到动态返回的效果,因此修改mytags文件如下

mytags文件

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')

#这里的v1就是给xx.html文件中引入hehe函数能够传一个参数
def hehe(v1):
return {'data':v1}

views文件

def xx(request):
#这里的lst就相当于从数据库中动态获取的数据
lst = ['唱1','跳1','rap1','篮球1']
return render(request,'xx.html',{'lst':lst})

xx.html文件

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %}
{% hehe lst %} //在这里引入views中定义的lst

最终真正的动态获取内容效果如下

iShot_2024-08-30_12.34.25

4.7 组件

组件类似于python中的模块,组件是把其他html页面引入过来,但是不能修改引入的文件的内容

组件文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</body>
</html>

iShot_2024-08-30_12.36.49

自定义文件

在自定义文件中,我们想引入组件文件中的列表样式,需要如下代码,这个就是在自定义文件中表示引入组件.html文件

#写法
{% include '组件.html' %}

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.c1{
background-color: green;
}
</style>
</head>
<body>
{% include '组件.html' %}
<div class="c1">我是一个引入了组件文件的自定义文件</div>
</body>
</html>

iShot_2024-08-30_12.38.28

4.8 模版继承

我们在写多个静态页面的时候可能会有一些相同的样式,这样的话每写一个页面就需要复制相同的代码,这样就造成了代码大量重复,此时就用到了模版继承,我们可以把相同样式的页面的代码单独放在一个模版文件中,其余页面继承这个模版文件,然后在设置自定义内容即可,这样就不用重复写相同样式的代码了

模版文件 base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.nav{
background-color: pink;
height: 40px;
}
.left-menu{
display: inline-block;
width: 200px;
background-color: mediumpurple;
}
.content{
display: inline-block;
height: 200px;
width: 600px;
background-color: burlywood;
color:white;
}
ul{
padding: 0;
margin: 0;
}

</style>

#这里表示预留css样式,子模版继承后可以修改模版的样式
{% block css %}
{% endblock %}
</head>
<body>

<div class="nav">
<a href="">个人中心</a>
<a href="">登录|注册</a>
</div>

<div class="left-menu">
<ul>
<li>
<a href="/menu01/">菜单1</a>
</li>
<li>
<a href="/menu02/">菜单2</a>
</li>
<li>
<a href="">菜单3</a>
</li>
</ul>
</div>

<div class="content">
{% block content %}
base页面
<a href="">xxx</a>
{% endblock %}

</div>
</body>
{% block js %}

{% endblock %}
</html>

模版继承的写法

在模版html文件中需要用到block方法,例如上述示例中,我们想要菜单1和菜单2有自己的自定义界面而不继承模版文件,写法如下
<div class="content">
{% block content %}
base页面
<a href="">xxx</a>
{% endblock %}
</div>


<div class="content">这个标签就是菜单1和菜单2中需要单独设置样式的标签,为了不继承模版文件,需要在这个标签写如下内容
block中包含的a标签就是菜单1和菜单2的html文件中需要重写的

{% block content %}
base页面
<a href="">xxx</a>
{% endblock %}
这段代码的意思是,模版文件中的base页面不希望被继承,这里就单独把这个页面预留出来,接下来在菜单1和菜单2的html文件中在单独写这块的样式,写法如下

//这里表示继承模版文件base.html
{% extends 'base.html' %}

因为不需要继承模版文件中的 base页面 处的内容,而模版文件中也把这一块内容已经预留出来了,并且定义了预留名称为 content,在菜单1和菜单2的html文件中之需要引入这个模版预留名称,这样就可以自定义自己的样式了,写法如下

{% block content %}
菜单1的内容
{% endblock %}

iShot_2024-08-30_12.40.06

base.html文件如上,现在我们设置菜单1、菜单2的自定义内容,需要做以下操作

urls文件

from app01 import views

urlpatterns = [
url(r'^admin/', admin.site.urls),
#这个就是模版页面
url(r'^base/', views.base),

#下边两个是菜单1和菜单2返回的页面
url(r'^menu01/', views.menu01),
url(r'^menu02/', views.menu02),
]

views文件

def base(request):
return render(request,'base.html')

def menu01(request):
return render(request,'menu01.html')

def menu02(request):
return render(request,'menu02.html')

menu01.html

{% extends 'base.html' %}
<style>
.content{
display: inline-block;
height: 200px;
width: 600px;
background-color: green;
color:white;
}
</style>
{% endblock %}

{% block content %}
菜单1的内容
{% endblock %}

menu02.html

{% extends 'base.html' %}

{% block content %}
菜单2的内容
{% endblock %}

访问base页面,点击菜单1,返回页面如下,因为在menu01.html文件中,我门自己指定了样式,因此背景颜色就和模版的不同了

iShot_2024-08-30_12.42.22

访问base页面,点击菜单2,返回页面如下

iShot_2024-08-30_12.43.34

block.super()

这个方法就是继承模板预留块的内容的同时在自定义内容

{% block content %}
{{ block.super }} #将模版中的content这个名称的块中的内容拿过来
菜单1的内容
{% endblock %}

4.9 url别名和反向解析

url别名的作用是当修改了url的访问路径,视图逻辑中返回的url路径也需要改动,其他相关联的地方也可能需要改动,这个时候我们在url中定义一个别名,如果后续更改了url的访问路径,其他地方只需要用到url别名的反向解析就能自动找到别名对应的url路径,这样的话只需要修改url路径而不更改其余地方

写法:
url(r'^login/v2/', views.login,name='login'),

视图中反向解析:
from django.urls import reverse

def login(request):
print(reverse('login')) #/login/v2/
if request.method == 'GET':
return render(request,'login.html')
else:
uname = request.POST.get('uname')
pwd = request.POST.get('pwd')
if uname == 'admin' and pwd == 'admin':

return HttpResponse('ok')
else:
return redirect(reverse('login')) #使用反向解析



html模板渲染时反向解析的语法{% url 别名 %}
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
用户名:<input type="text" name="uname">
密码:<input type="text" name="pwd">
<input type="submit">
</form>

进行html模板渲染时反向解析时,如果定义了命名空间,则在html中需要如下写法

html模板渲染时反向解析的语法{% url 命名空间:别名 %}

4.10 include路由分发和url命名空间

4.10.1 include路由分发

include路由分发就是将不同的url放在不同的应用程序下的urls文件中,先匹配一个应用程序的路径,然后在分别去这两个应用程序对应的urls文件中找下一级目录

例如,现在有app01和app02两个应用程序,现在设置的访问路径如下

/app01/index

/app02/index

访问到app01就去app01路径下找index

Right Bottom Gif
Right Top GIF